home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / ANSI / c-client / os_sco.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-06  |  22.3 KB  |  821 lines

  1. /*
  2.  * Program:    Operating-system dependent routines -- ANSI SCO Unix version
  3.  *
  4.  * Author:    Mark Crispin/Ken Bobey
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    11 May 1992
  13.  * Last Edited:    6 July 1993
  14.  *
  15.  * Copyright 1993 by the University of Washington.
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made available
  24.  * "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36. /* TCP input buffer */
  37.  
  38. #define BUFLEN 8192
  39.  
  40.  
  41. /* TCP I/O stream (must be before osdep.h is included) */
  42.  
  43. #define TCPSTREAM struct tcp_stream
  44. TCPSTREAM {
  45.   char *host;            /* host name */
  46.   char *localhost;        /* local host name */
  47.   int tcpsi;            /* input socket */
  48.   int tcpso;            /* output socket */
  49.   int ictr;            /* input counter */
  50.   char *iptr;            /* input pointer */
  51.   char ibuf[BUFLEN];        /* input buffer */
  52. };
  53.  
  54.  
  55. #include "mail.h"
  56. #include "osdep.h"
  57. #include <sys/time.h>
  58. #include <sys/socket.h>
  59. #include <sys/stat.h>
  60. #include <netinet/in.h>
  61. #include <netdb.h>
  62. extern int h_errno;        /* not defined in netdb.h */
  63. #include <ctype.h>
  64. #include <errno.h>
  65. #include <syslog.h>
  66. #include <utime.h>
  67. #include "misc.h"
  68. #define SecureWare              /* protected subsystem */
  69. #include <sys/security.h>
  70. #include <sys/audit.h>
  71. #include <prot.h>
  72. #include <pwd.h>
  73.  
  74. extern char *crypt();
  75. static char *re;
  76. extern char *regcmp (char *str,char *z);
  77. extern char *regex (char *re,char *s);
  78.  
  79. /* Write current time in RFC 822 format
  80.  * Accepts: destination string
  81.  */
  82.  
  83. char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  84.  
  85. void rfc822_date (char *date)
  86. {
  87.   int zone,dstflag;
  88.   struct tm *t;
  89.   struct timeval tv;
  90.   struct timezone tz;
  91.   gettimeofday (&tv,&tz);    /* get time and timezone poop */
  92.   t = localtime (&tv.tv_sec);    /* convert to individual items */
  93.   tzset ();            /* get timezone from TZ environment stuff */
  94.   dstflag = daylight ? t->tm_isdst : 0;
  95.   zone = (dstflag * 60) - timezone/60;
  96.                 /* and output it */
  97.   sprintf (date,"%s, %d %s %d %02d:%02d:%02d %+02d%02d (%s)",
  98.        days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
  99.        t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60,
  100.        tzname[dstflag]);
  101. }
  102.  
  103. /* Get a block of free storage
  104.  * Accepts: size of desired block
  105.  * Returns: free storage block
  106.  */
  107.  
  108. void *fs_get (size_t size)
  109. {
  110.   void *block = malloc (size);
  111.   if (!block) fatal ("Out of free storage");
  112.   return (block);
  113. }
  114.  
  115.  
  116. /* Resize a block of free storage
  117.  * Accepts: ** pointer to current block
  118.  *        new size
  119.  */
  120.  
  121. void fs_resize (void **block,size_t size)
  122. {
  123.   if (!(*block = realloc (*block,size))) fatal ("Can't resize free storage");
  124. }
  125.  
  126.  
  127. /* Return a block of free storage
  128.  * Accepts: ** pointer to free storage block
  129.  */
  130.  
  131. void fs_give (void **block)
  132. {
  133.   if (*block != NIL)
  134.     free (*block);
  135.   *block = NIL;
  136. }
  137.  
  138.  
  139. /* Report a fatal error
  140.  * Accepts: string to output
  141.  */
  142.  
  143. void fatal (char *string)
  144. {
  145.   mm_fatal (string);        /* pass up the string */
  146.   syslog (LOG_ALERT,"IMAP C-Client crash: %s",string);
  147.   abort ();            /* die horribly */
  148. }
  149.  
  150. /* Copy string with CRLF newlines
  151.  * Accepts: destination string
  152.  *        pointer to size of destination string
  153.  *        source string
  154.  *        length of source string
  155.  */
  156.  
  157. char *strcrlfcpy (char **dst,unsigned long *dstl,char *src,unsigned long srcl)
  158. {
  159.   long i,j;
  160.   char *d = src;
  161.                 /* count number of LF's in source string(s) */
  162.   for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
  163.   if (i > *dstl) {        /* resize if not enough space */
  164.     fs_give ((void **) dst);    /* fs_resize does an unnecessary copy */
  165.     *dst = (char *) fs_get ((*dstl = i) + 1);
  166.   }
  167.   d = *dst;            /* destination string */
  168.                 /* copy strings, inserting CR's before LF's */
  169.   while (srcl--) switch (*src) {
  170.   case '\015':            /* unlikely carriage return */
  171.     *d++ = *src++;        /* copy it and any succeeding linefeed */
  172.     if (srcl && *src == '\012') {
  173.       *d++ = *src++;
  174.       srcl--;
  175.     }
  176.     break;
  177.   case '\012':            /* line feed? */
  178.     *d++ ='\015';        /* yes, prepend a CR, drop into default case */
  179.   default:            /* ordinary chararacter */
  180.     *d++ = *src++;        /* just copy character */
  181.     break;
  182.   }
  183.   *d = '\0';            /* tie off destination */
  184.   return *dst;            /* return destination */
  185. }
  186.  
  187.  
  188. /* Length of string after strcrlfcpy applied
  189.  * Accepts: source string
  190.  *        length of source string
  191.  */
  192.  
  193. unsigned long strcrlflen (STRING *s)
  194. {
  195.   unsigned long pos = GETPOS (s);
  196.   unsigned long i = SIZE (s);
  197.   unsigned long j = i;
  198.   while (j--) switch (SNX (s)) {/* search for newlines */
  199.   case '\015':            /* unlikely carriage return */
  200.     if (j && (CHR (s) == '\012')) {
  201.       SNX (s);            /* eat the line feed */
  202.       j--;
  203.     }
  204.     break;
  205.   case '\012':            /* line feed? */
  206.     i++;
  207.   default:            /* ordinary chararacter */
  208.     break;
  209.   }
  210.   SETPOS (s,pos);        /* restore old position */
  211.   return i;
  212. }
  213.  
  214. /* Server log in
  215.  * Accepts: user name string
  216.  *        password string
  217.  *        optional place to return home directory
  218.  * Returns: T if password validated, NIL otherwise
  219.  */
  220.  
  221. static struct passwd *pwd = NIL;/* used by Geteuid() */
  222.  
  223. long server_login (char *user,char *pass,char **home,int argc,char *argv[])
  224. {
  225.   struct pr_passwd *pw;
  226.   set_auth_parameters (argc,argv);
  227.                 /* see if this user code exists */
  228.   if (!(pw = getprpwnam (lcase (user)))) return NIL;
  229.                 /* Encrypt the given password string */
  230.   if (strcmp (pw->ufld.fd_encrypt,(char *) crypt (pass,pw->ufld.fd_encrypt)))
  231.     return NIL;
  232.   pwd = getpwnam (user);    /* all OK, get the public information */
  233.   setgid (pwd->pw_gid);        /* login in as that user */
  234.   setuid (pwd->pw_uid);
  235.                 /* note home directory */
  236.   if (home) *home = cpystr (pwd->pw_dir);
  237.   return T;
  238. }
  239.  
  240. /* Return my user name
  241.  * Returns: my user name
  242.  */
  243.  
  244. char *myuname = NIL;
  245.  
  246. char *myusername ()
  247. {
  248.   return myuname ? myuname : (myuname = cpystr(getpwuid(geteuid ())->pw_name));
  249. }
  250.  
  251.  
  252. /* Return my home directory name
  253.  * Returns: my home directory name
  254.  */
  255.  
  256. char *hdname = NIL;
  257.  
  258. char *myhomedir ()
  259. {
  260.   return hdname ? hdname : (hdname = cpystr (getpwuid (geteuid ())->pw_dir));
  261. }
  262.  
  263.  
  264. /* Build status lock file name
  265.  * Accepts: scratch buffer
  266.  *        file name
  267.  * Returns: name of file to lock
  268.  */
  269.  
  270. char *lockname (char *tmp,char *fname)
  271. {
  272.   char *s = strrchr (fname,'/');
  273.   struct stat sbuf;
  274.   if (stat (fname,&sbuf))    /* get file status */
  275.     sprintf (tmp,"/tmp/.%s",s ? s : fname);
  276.   else sprintf (tmp,"/tmp/.%hx.%lx",sbuf.st_dev,sbuf.st_ino);
  277.   return tmp;            /* note name for later */
  278. }
  279.   
  280. /* TCP/IP open
  281.  * Accepts: host name
  282.  *        contact port number
  283.  * Returns: TCP/IP stream if success else NIL
  284.  */
  285.  
  286. TCPSTREAM *tcp_open (char *host,int port)
  287. {
  288.   TCPSTREAM *stream = NIL;
  289.   int sock;
  290.   char *s;
  291.   struct sockaddr_in sin;
  292.   struct hostent *host_name;
  293.   char hostname[MAILTMPLEN];
  294.   char tmp[MAILTMPLEN];
  295.   /* The domain literal form is used (rather than simply the dotted decimal
  296.      as with other Unix programs) because it has to be a valid "host name"
  297.      in mailsystem terminology. */
  298.                 /* look like domain literal? */
  299.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  300.     strcpy (hostname,host+1);    /* yes, copy number part */
  301.     hostname[(strlen (hostname))-1] = '\0';
  302.     if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
  303.       sin.sin_family = AF_INET;    /* family is always Internet */
  304.       strcpy (hostname,host);    /* hostname is user's argument */
  305.     }
  306.     else {
  307.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  308.       mm_log (tmp,ERROR);
  309.       return NIL;
  310.     }
  311.   }
  312.  
  313.   else {            /* lookup host name, note that brain-dead Unix
  314.                    requires lowercase! */
  315.     strcpy (hostname,host);    /* in case host is in write-protected memory */
  316.     if ((host_name = gethostbyname (lcase (hostname)))) {
  317.                 /* copy address type */
  318.       sin.sin_family = host_name->h_addrtype;
  319.                 /* copy host name */
  320.       strcpy (hostname,host_name->h_name);
  321.                 /* copy host addresses */
  322.       memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
  323.     }
  324.     else {
  325.       switch (h_errno) {
  326.     case HOST_NOT_FOUND:    /* authoritative error */
  327.       s = "No such host as %.80s";
  328.       break;
  329.     case TRY_AGAIN:        /* non-authoritative error */
  330.       s = "Transient error for host %.80s, try again";
  331.       break;
  332.     case NO_RECOVERY:    /* non-recoverable errors */
  333.       s = "Non-recoverable error looking up host %.80s";
  334.       break;
  335.     case NO_DATA:        /* no data record of requested type */
  336.       s = "No IP address known for host %.80s";
  337.       break;
  338.     default:
  339.       s = "Unknown error for host %.80s";
  340.       break;
  341.       }
  342.       sprintf (tmp,s,host);
  343.       mm_log (tmp,ERROR);
  344.       return NIL;
  345.     }
  346.   }
  347.  
  348.                 /* copy port number in network format */
  349.   if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
  350.                 /* get a TCP stream */
  351.   if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
  352.     sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
  353.     mm_log (tmp,ERROR);
  354.     return NIL;
  355.   }
  356.                 /* open connection */
  357.   if (connect (sock,(struct sockaddr *)&sin,sizeof (sin)) < 0) {
  358.     sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
  359.          strerror (errno));
  360.     mm_log (tmp,ERROR);
  361.     return NIL;
  362.   }
  363.                 /* create TCP/IP stream */
  364.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  365.                 /* copy official host name */
  366.   stream->host = cpystr (hostname);
  367.                 /* get local name */
  368.   gethostname (tmp,MAILTMPLEN-1);
  369.   stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
  370.                   host_name->h_name : tmp);
  371.                 /* init sockets */
  372.   stream->tcpsi = stream->tcpso = sock;
  373.   stream->ictr = 0;        /* init input counter */
  374.   return stream;        /* return success */
  375. }
  376.   
  377. /* TCP/IP authenticated open
  378.  * Accepts: host name
  379.  *        service name
  380.  * Returns: TCP/IP stream if success else NIL
  381.  */
  382.  
  383. TCPSTREAM *tcp_aopen (char *host,char *service)
  384. {
  385.   TCPSTREAM *stream = NIL;
  386.   struct hostent *host_name;
  387.   char hostname[MAILTMPLEN];
  388.   int i;
  389.   int pipei[2],pipeo[2];
  390.   /* The domain literal form is used (rather than simply the dotted decimal
  391.      as with other Unix programs) because it has to be a valid "host name"
  392.      in mailsystem terminology. */
  393.                 /* look like domain literal? */
  394.   if (host[0] == '[' && host[i = (strlen (host))-1] == ']') {
  395.     strcpy (hostname,host+1);    /* yes, copy without brackets */
  396.     hostname[i-1] = '\0';
  397.   }
  398.                 /* note that Unix requires lowercase! */
  399.   else if (host_name = gethostbyname (lcase (strcpy (hostname,host))))
  400.     strcpy (hostname,host_name->h_name);
  401.                 /* make command pipes */
  402.   if (pipe (pipei) < 0) return NIL;
  403.   if (pipe (pipeo) < 0) {
  404.     close (pipei[0]); close (pipei[1]);
  405.     return NIL;
  406.   }
  407.   if ((i = fork ()) < 0) {    /* make inferior process */
  408.     close (pipei[0]); close (pipei[1]);
  409.     close (pipeo[0]); close (pipeo[1]);
  410.     return NIL;
  411.   }
  412.   if (i) {            /* parent? */
  413.     close (pipei[1]);        /* close child's side of the pipes */
  414.     close (pipeo[0]);
  415.   }
  416.   else {            /* child */
  417.     dup2 (pipei[1],1);        /* parent's input is my output */
  418.     dup2 (pipei[1],2);        /* parent's input is my error output too */
  419.     close (pipei[0]); close (pipei[1]);
  420.     dup2 (pipeo[0],0);        /* parent's output is my input */
  421.     close (pipeo[0]); close (pipeo[1]);
  422.                 /* now run it */
  423.     execl ("/usr/ucb/rsh","rsh",hostname,"exec",service,0);
  424.     _exit (1);            /* spazzed */
  425.   }
  426.  
  427.                 /* create TCP/IP stream */
  428.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  429.                 /* copy official host name */
  430.   stream->host = cpystr (hostname);
  431.                 /* get local name */
  432.   gethostname (hostname,MAILTMPLEN-1);
  433.   stream->localhost = cpystr ((host_name = gethostbyname (hostname)) ?
  434.                   host_name->h_name : hostname);
  435.   stream->tcpsi = pipei[0];    /* init sockets */
  436.   stream->tcpso = pipeo[1];
  437.   stream->ictr = 0;        /* init input counter */
  438.   return stream;        /* return success */
  439. }
  440.  
  441. /* TCP/IP receive line
  442.  * Accepts: TCP/IP stream
  443.  * Returns: text line string or NIL if failure
  444.  */
  445.  
  446. char *tcp_getline (TCPSTREAM *stream)
  447. {
  448.   int n,m;
  449.   char *st,*ret,*stp;
  450.   char c = '\0';
  451.   char d;
  452.                 /* make sure have data */
  453.   if (!tcp_getdata (stream)) return NIL;
  454.   st = stream->iptr;        /* save start of string */
  455.   n = 0;            /* init string count */
  456.   while (stream->ictr--) {    /* look for end of line */
  457.     d = *stream->iptr++;    /* slurp another character */
  458.     if ((c == '\015') && (d == '\012')) {
  459.       ret = (char *) fs_get (n--);
  460.       memcpy (ret,st,n);    /* copy into a free storage string */
  461.       ret[n] = '\0';        /* tie off string with null */
  462.       return ret;
  463.     }
  464.     n++;            /* count another character searched */
  465.     c = d;            /* remember previous character */
  466.   }
  467.                 /* copy partial string from buffer */
  468.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  469.                 /* get more data from the net */
  470.   if (!tcp_getdata (stream)) return NIL;
  471.                 /* special case of newline broken by buffer */
  472.   if ((c == '\015') && (*stream->iptr == '\012')) {
  473.     stream->iptr++;        /* eat the line feed */
  474.     stream->ictr--;
  475.     ret[n - 1] = '\0';        /* tie off string with null */
  476.   }
  477.                 /* else recurse to get remainder */
  478.   else if (st = tcp_getline (stream)) {
  479.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  480.     memcpy (ret,stp,n);        /* copy first part */
  481.     memcpy (ret + n,st,m);    /* and second part */
  482.     fs_give ((void **) &stp);    /* flush first part */
  483.     fs_give ((void **) &st);    /* flush second part */
  484.     ret[n + m] = '\0';        /* tie off string with null */
  485.   }
  486.   return ret;
  487. }
  488.  
  489. /* TCP/IP receive buffer
  490.  * Accepts: TCP/IP stream
  491.  *        size in bytes
  492.  *        buffer to read into
  493.  * Returns: T if success, NIL otherwise
  494.  */
  495.  
  496. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  497. {
  498.   unsigned long n;
  499.   char *bufptr = buffer;
  500.   while (size > 0) {        /* until request satisfied */
  501.     if (!tcp_getdata (stream)) return NIL;
  502.     n = min (size,stream->ictr);/* number of bytes to transfer */
  503.                 /* do the copy */
  504.     memcpy (bufptr,stream->iptr,n);
  505.     bufptr += n;        /* update pointer */
  506.     stream->iptr +=n;
  507.     size -= n;            /* update # of bytes to do */
  508.     stream->ictr -=n;
  509.   }
  510.   bufptr[0] = '\0';        /* tie off string */
  511.   return T;
  512. }
  513.  
  514.  
  515. /* TCP/IP receive data
  516.  * Accepts: TCP/IP stream
  517.  * Returns: T if success, NIL otherwise
  518.  */
  519.  
  520. long tcp_getdata (TCPSTREAM *stream)
  521. {
  522.   fd_set fds;
  523.   FD_ZERO (&fds);        /* initialize selection vector */
  524.   if (stream->tcpsi < 0) return NIL;
  525.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  526.     FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
  527.                 /* block and read */
  528.     if ((select (stream->tcpsi+1,&fds,0,0,0) < 0) ||
  529.     ((stream->ictr = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 1)) {
  530.       close (stream->tcpsi);    /* nuke the socket */
  531.       if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  532.       stream->tcpsi = stream->tcpso = -1;
  533.       return NIL;
  534.     }
  535.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  536.   }
  537.   return T;
  538. }
  539.  
  540. /* TCP/IP send string as record
  541.  * Accepts: TCP/IP stream
  542.  *        string pointer
  543.  * Returns: T if success else NIL
  544.  */
  545.  
  546. long tcp_soutr (TCPSTREAM *stream,char *string)
  547. {
  548.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  549. }
  550.  
  551.  
  552. /* TCP/IP send string
  553.  * Accepts: TCP/IP stream
  554.  *        string pointer
  555.  *        byte count
  556.  * Returns: T if success else NIL
  557.  */
  558.  
  559. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  560. {
  561.   int i;
  562.   fd_set fds;
  563.   FD_ZERO (&fds);        /* initialize selection vector */
  564.   if (stream->tcpso < 0) return NIL;
  565.   while (size > 0) {        /* until request satisfied */
  566.     FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
  567.     if ((select (stream->tcpso+1,0,&fds,0,0) < 0) ||
  568.     ((i = write (stream->tcpso,string,size)) < 0)) {
  569.       puts (strerror (errno));
  570.       close (stream->tcpsi);    /* nuke the socket */
  571.       if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  572.       stream->tcpsi = stream->tcpso = -1;
  573.       return NIL;
  574.     }
  575.     size -= i;            /* count this size */
  576.     string += i;
  577.   }
  578.   return T;            /* all done */
  579. }
  580.  
  581. /* TCP/IP close
  582.  * Accepts: TCP/IP stream
  583.  */
  584.  
  585. void tcp_close (TCPSTREAM *stream)
  586. {
  587.  
  588.   if (stream->tcpsi >= 0) {    /* no-op if no socket */
  589.     close (stream->tcpsi);    /* nuke the socket */
  590.     if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
  591.     stream->tcpsi = stream->tcpso = -1;
  592.   }
  593.                 /* flush host names */
  594.   fs_give ((void **) &stream->host);
  595.   fs_give ((void **) &stream->localhost);
  596.   fs_give ((void **) &stream);    /* flush the stream */
  597. }
  598.  
  599.  
  600. /* TCP/IP get host name
  601.  * Accepts: TCP/IP stream
  602.  * Returns: host name for this stream
  603.  */
  604.  
  605. char *tcp_host (TCPSTREAM *stream)
  606. {
  607.   return stream->host;        /* return host name */
  608. }
  609.  
  610.  
  611. /* TCP/IP get local host name
  612.  * Accepts: TCP/IP stream
  613.  * Returns: local host name
  614.  */
  615.  
  616. char *tcp_localhost (TCPSTREAM *stream)
  617. {
  618.   return stream->localhost;    /* return local host name */
  619. }
  620.  
  621.  
  622. /* Copy memory block
  623.  * Accepts: destination pointer
  624.  *        source pointer
  625.  *        length
  626.  * Returns: destination pointer
  627.  */
  628.  
  629. void *memmove (void *s, void *ct, size_t n)
  630. {
  631.   char *dp, *sp;
  632.   int i;
  633.   unsigned long dest = (unsigned long) s;
  634.   unsigned long src = (unsigned long) ct;
  635.   if (((dest < src) && ((dest + n) < src)) ||
  636.       ((dest > src) && ((src + n) < dest))) return memcpy (s, ct, n);
  637.   dp = s;
  638.   sp = ct;
  639.   if (dest < src) for (i = 0; i < n; ++i) dp[i] = sp[i];
  640.   else if (dest > src) for (i = n - 1; i >= 0; --i) dp[i] = sp[i];
  641.   return s;
  642. }
  643.  
  644.  
  645. /* Get host ID
  646.  * Returns: host ID
  647.  */
  648.  
  649. unsigned long gethostid ()
  650. {
  651.   return (unsigned long) 0xdeadface;
  652. }
  653.  
  654. /* Emulator for BSD random() call
  655.  * Returns: long random number
  656.  */
  657.  
  658. long random ()
  659. {
  660.   return ((long) rand ());
  661. }
  662.  
  663.  
  664. /* Emulator for BSD ftruncate() call
  665.  * Accepts: file descriptor
  666.  *        length
  667.  * Returns: 0 if successful, else -1
  668.  */
  669. int ftruncate (int fd, off_t length)
  670. {
  671.   return chsize (fd, length);
  672. }
  673.  
  674. /* Emulator for BSD scandir() call
  675.  * Accepts: directory name
  676.  *        destination pointer of names array
  677.  *        selection function
  678.  *        comparison function
  679.  * Returns: number of elements in the array or -1 if error
  680.  */
  681.  
  682. #define DIR_SIZE(d) d->d_reclen
  683.  
  684. int scandir (char *dirname, struct dirent ***namelist, int (*select) (), int (*compar) ())
  685. {
  686.   struct dirent *p,*d,**names;
  687.   int nitems;
  688.   struct stat stb;
  689.   long nlmax;
  690.   DIR *dirp = opendir (dirname);/* open directory and get status poop */
  691.   if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1;
  692.   nlmax = stb.st_size / 24;    /* guesstimate at number of files */
  693.   names = (struct dirent **) fs_get (nlmax * sizeof (struct dirent *));
  694.   nitems = 0;            /* initially none found */
  695.   while (d = readdir (dirp)) {    /* read directory item */
  696.                 /* matches select criterion? */
  697.     if (select && !(*select) (d)) continue;
  698.                 /* get size of dirent record for this file */
  699.     p = (struct dirent *) fs_get (DIR_SIZE (d));
  700.     p->d_ino = d->d_ino;    /* copy the poop */
  701.     p->d_off = d->d_off;
  702.     p->d_reclen = d->d_reclen;
  703.     strcpy (d->d_name,p->d_name);
  704.     if (++nitems >= nlmax) {    /* if out of space, try bigger guesstimate */
  705.       nlmax *= 2;        /* double it */
  706.       fs_resize ((void **) names,nlmax * sizeof (struct dirent *));
  707.     }
  708.     names[nitems - 1] = p;    /* store this file there */
  709.   }
  710.   closedir (dirp);        /* done with directory */
  711.                 /* sort if necessary */
  712.   if (nitems && compar) qsort (names,nitems,sizeof (struct dirent *),compar);
  713.   *namelist = names;        /* return directory */
  714.   return nitems;        /* and size */
  715. }
  716.  
  717. /* Emulator for BSD flock() call
  718.  * Accepts: file descriptor
  719.  *        operation bitmask
  720.  * Returns: 0 if successful, -1 if failure
  721.  * Note: this emulator does not handle shared locks
  722.  */
  723.  
  724. int flock (int fd,int operation)
  725. {
  726.   int func;
  727.   off_t offset = lseek (fd,0,L_INCR);
  728.   switch (operation & ~LOCK_NB){/* translate to lockf() operation */
  729.   case LOCK_EX:            /* exclusive */
  730.   case LOCK_SH:            /* shared */
  731.     func = (operation & LOCK_NB) ? F_TLOCK : F_LOCK;
  732.     break;
  733.   case LOCK_UN:            /* unlock */
  734.     func = F_ULOCK;
  735.     break;
  736.   default:            /* default */
  737.     errno = EINVAL;
  738.     return -1;
  739.   }
  740.   lseek (fd,0,L_SET);        /* position to start of the file */
  741.   func = lockf (fd,func,0);    /* do the lockf() */
  742.   lseek (fd,offset,L_SET);    /* restore prior position */
  743.   return func;
  744. }
  745.  
  746.  
  747. /* Emulator for BSD utimes() call
  748.  * Accepts: file name
  749.  *        timeval vector for access and updated time
  750.  * Returns: 0 if successful, -1 if failure
  751.  */
  752.  
  753. int utimes (char *file, struct timeval tvp[2])
  754. {
  755.   struct utimbuf tb;
  756.   tb.actime = tvp[0].tv_sec;    /* accessed time */
  757.   tb.modtime = tvp[1].tv_sec;    /* updated time */
  758.   return utime (file,&tb);
  759. }
  760.  
  761. /* Emulator for BSD writev() call
  762.  * Accepts: file name
  763.  *        I/O vector structure
  764.  *        Number of vectors in structure
  765.  * Returns: 0 if successful, -1 if failure
  766.  */
  767.  
  768. int writev (int fd, struct iovec *iov, int iovcnt)
  769. {
  770.   int c, cnt;
  771.   if (iovcnt <=0) return (-1);
  772.   for (cnt=0; iovcnt != 0; iovcnt--, iov++)
  773.   {
  774.     c = write(fd, iov->iov_base, iov->iov_len);
  775.     if (c < 0) return (-1);
  776.     cnt += c;
  777.   }
  778.   return (cnt);
  779. }
  780.  
  781.  
  782. /* Emulator for BSD fsync() call
  783.  * Accepts: file name
  784.  * Returns: 0 if successful, -1 if failure
  785.  */
  786.  
  787. int fsync (int fd)
  788. {
  789.   sync ();
  790.   return (0);
  791. }
  792.  
  793. /* Emulator for BSD setitimer() call
  794.  * Accepts: which timer to set
  795.  *        new timer value
  796.  *        previous timer value
  797.  * Returns: 0 if successful, -1 if failure
  798.  */
  799.  
  800. int setitimer(int which, struct itimerval *val, struct itimerval *oval)
  801. {
  802.   (void) alarm ((unsigned)val->it_value.tv_sec);
  803.   return (0);
  804. }
  805.  
  806.  
  807. /* Emulator for geteuid()
  808.  * I'm not quite sure why this is done; it was this way in the code Ken sent
  809.  * me.  It only had the comment ``EUIDs don't work on SCO!''.  I think it has
  810.  * something to do with the set_auth_parameters() stuff in server_login().
  811.  *
  812.  * Someone with expertise in SCO (and with an SCO system to hack) should look
  813.  * into this and figure out what's going on.
  814.  */
  815.  
  816. int Geteuid ()
  817. {
  818.                 /* if server_login called, use its UID */
  819.   return pwd ? (pwd->pw_uid) : getuid ();
  820. }
  821.